#ifndef _B_PLUS_TREE_LEAF_STORAGE_HPP__
#define _B_PLUS_TREE_LEAF_STORAGE_HPP__ 1
#include <BPlusTreeNodeLeafData.hpp>
#include <BPlusNodeLeaf.hpp>
#include <Storage.hpp>
#include <Types.h>

namespace FTSS { // Full Text Search System
	class BPlusTreeLeafsStorage : Storage {
		public : 
			/**
			  * @brief Constructor
			  */
			BPlusTreeLeafsStorage(CCHAR_P storage_name, CCHAR_P empty_blocks) : 
									Storage(storage_name, empty_blocks){};
	
			/**
			  * @brief restore leaf from HDD storage
			  * @param pointer to leaf or NULL if not success restore
			  */
			template <typename T, typename V, INT_64 TreeWidth>
			BPlusLeaf<T, V, TreeWidth>* GetLeafById(INT_32 leaf_id){
				// because leaf id < 0
				if (leaf_id < 0) leaf_id = -leaf_id;
				if (leaf_id < length_data){
					BPlusLeaf<T, V, TreeWidth> *pRes = new BPlusLeaf<T, V, TreeWidth>();
					CHAR_P src = storage_data_mmap + 2 * sizeof(INT_64) + 
										leaf_id * BPlusLeaf<T, V, TreeWidth>::getSizeOf();
					if(memcpy(pRes, src, sizeof(*pRes)) != pRes) {
						fprintf(stderr, "memcpy broken in storage leaf get by id");
						throw UnixException(errno, "memcpy broken in storage leaf get by id");
					}
					src += sizeof(*pRes);
					for (INT_32 iI = 0; iI < pRes->size; ++iI){
						CHAR_P restored_data = new CHAR_8[BPlusTreeLeafData::getSizeData()];
						INT_32 cur_size = pRes->pairs[iI].value.iDataSize;
						memcpy(restored_data, src, cur_size);
						pRes->pairs[iI].value.pData = restored_data;
						pRes->pairs[iI].value.iDataSize = cur_size;
						src += cur_size;
					}
					return pRes;
				}
				return NULL;
			}

			/**	
			 * @brief DumpNode to white space of storage or to the end of file 
			 * and generate node id and return it if -leaf_id == -1
			 * else dump leaf to the leaf with leaf_id
			 * @return restored leaf id
			*/
			template <typename T, typename V, INT_64 TreeWidth>
			INT_32 DumpLeaf(BPlusLeaf<T, V, TreeWidth> *pLeaf){
				INT_32 current_leaf_id;
				if (pLeaf != NULL && pLeaf->id != 0) {
					// because id < 0
					current_leaf_id = -pLeaf->id;
					if (current_leaf_id > length_data) length_data = current_leaf_id;
				} else if (length_stack != 0){
					current_leaf_id = vector_data_mmap[length_stack + 1];
					--length_stack;
				} else {
					current_leaf_id = length_data;
					++length_data;
				}
				//remmaping
				INT_32 size_tmp = BPlusLeaf<T, V, TreeWidth>::getSizeOf();
				if ( ((current_leaf_id + 1)* size_tmp + (INT_32)(2 * sizeof(INT_64))) >= size_storage_nodes ){
					if (ReMMAP(data_storageHandler) != 0)
						throw UnixException(errno, "remmap leaf storage fails");
				}
				// get new id and preemt new id for leaf
				if (pLeaf != NULL) {
					pLeaf-> id = - current_leaf_id;
					CHAR_P dest = storage_data_mmap + 2 * sizeof(INT_64) + current_leaf_id * size_tmp;
					memcpy (dest, (CHAR_P)pLeaf, sizeof(*pLeaf));
					dest += sizeof(*pLeaf);
					for (INT_32 iI = 0; iI < pLeaf->size; ++iI){
						INT_32 cur_size = pLeaf->pairs[iI].value.iDataSize;
						memcpy(dest, pLeaf->pairs[iI].value.pData, cur_size);
						dest += cur_size;
					}
				}
				return -current_leaf_id;
			}

			/**
			 * @brief Delete Leaf (not really delete, add leaf_id to the white space vector)
			 * @return 0 if success, -1 if something wrong 
			 */
			INT_32  DeleteLeaf(INT_32 leaf_id){
				if (length_stack + 2 >= (size_vector_file / sizeof(INT_64))){
					if (ReMMAP(vector_empty_blocksHandler) != 0)
					throw UnixException(errno, "remmap vector empty block fails");
				}
				if (leaf_id < length_data){
					vector_data_mmap[length_stack + 2] = leaf_id;
					++length_stack;
					return 0;
				}
				return -1;
			}

			/*
			* @brief Destructor
			*/
			virtual ~BPlusTreeLeafsStorage() throw() {};

	}; // B Plus Tree Leafs Storage
}// FTSS
#endif
